﻿Public Class Service
    Implements IDisposable

#Region " Color "

    Public Function GetColors() As Results(Of Color)
        Return GetColors(Nothing)
    End Function
    Public Function GetColors(ByVal query As ColorQuery) As Results(Of Color)
        Return CallMethod(Of Results(Of Color))("colors", query)
    End Function
    Public Function GetColor() As Color
        Return CallMethod(Of Results(Of Color))("colors/random").Items.First
    End Function
    Public Function GetColor(ByVal color As System.Drawing.Color) As Color
        Return GetColor(color.ToHTML)
    End Function
    Public Function GetColor(ByVal hex As String) As Color
        Return CallMethod(Of Results(Of Color))(String.Concat("color/", hex)).Items.First
    End Function

#End Region
#Region " Palette "

    Public Function GetPalettes() As Results(Of Palette)
        Return GetPalettes(Nothing)
    End Function
    Public Function GetPalettes(ByVal query As PaletteQuery) As Results(Of Palette)
        Return CallMethod(Of Results(Of Palette))("palettes", query)
    End Function
    Public Function GetPalette() As Palette
        Return CallMethod(Of Results(Of Palette))("palettes/random").Items.First
    End Function
    Public Function GetPalette(ByVal id As Integer) As Palette
        Return GetPalette(id, False)
    End Function
    Public Function GetPalette(ByVal id As Integer, ByVal showPaletteWidths As Boolean) As Palette
        Return CallMethod(Of Results(Of Palette))(
            String.Concat("palette/", id),
            New PaletteQuery With {
                .ShowPaletteWidths = showPaletteWidths}).Items.First
    End Function

#End Region
#Region " Pattern "

    Public Function GetPatterns() As Results(Of ColorList)
        Return GetPatterns(Nothing)
    End Function
    Public Function GetPatterns(ByVal query As PatternQuery) As Results(Of ColorList)
        Return CallMethod(Of Results(Of ColorList))("patterns", query)
    End Function
    Public Function GetPattern() As ColorList
        Return CallMethod(Of Results(Of ColorList))("patterns/random").Items.First
    End Function
    Public Function GetPattern(ByVal id As Integer) As ColorList
        Return CallMethod(Of Results(Of ColorList))(String.Concat("pattern/", id)).Items.First
    End Function

#End Region
#Region " Lover "

    Public Function GetLovers() As Results(Of Lover)
        Return GetLovers(Nothing)
    End Function
    Public Function GetLovers(ByVal query As Query) As Results(Of Lover)
        Return CallMethod(Of Results(Of Lover))("lovers", query)
    End Function
    Public Function GetLover(ByVal username As String) As Lover
        Return GetLover(username, False)
    End Function
    Public Function GetLover(ByVal username As String, ByVal comments As Boolean) As Lover
        Return CallMethod(Of Results(Of Lover))(String.Concat("lover/", username)).Items.First
    End Function

#End Region
#Region " Internal "
    Private _client As System.Net.WebClient
    Private Const _baseUri = "http://www.colourlovers.com/api/"

    Public Sub New()
        _client = New System.Net.WebClient With {
            .BaseAddress = _baseUri}
    End Sub

    Private Function CallMethod(Of T)(ByVal path As String) As T
        Return CallMethod(Of T)(path, Nothing)
    End Function
    Private Function CallMethod(Of T)(ByVal path As String, ByVal query As LoverQuery) As T
        If query IsNot Nothing Then
            path &= query.ToString
        End If

        Return _
             GetSerializer(Of T) _
             .Deserialize(
                 _client.OpenRead(
                     path))
    End Function
    Private Function GetSerializer(Of T)() As System.Xml.Serialization.XmlSerializer
        Return _
                New System.Xml.Serialization.XmlSerializer(
                    GetType(T),
                    Me.GetOverrides(Of T))
    End Function
    Private Function GetOverrides(Of T)() As System.Xml.Serialization.XmlAttributeOverrides
        Dim elementName As String = Nothing
        Dim rootName As String = Nothing

        Select Case GetType(T)
            Case GetType(Results(Of Color))
                elementName = "color"
                rootName = "colors"

            Case GetType(Results(Of Palette))
                elementName = "palette"
                rootName = "palettes"

            Case GetType(Results(Of ColorList))
                elementName = "pattern"
                rootName = "patterns"

        End Select

        Dim elementOverride = New System.Xml.Serialization.XmlAttributes
        elementOverride.XmlElements.Add(New System.Xml.Serialization.XmlElementAttribute(elementName))

        Dim attributeOverrides = New System.Xml.Serialization.XmlAttributeOverrides

        attributeOverrides.Add(GetType(T), "Items", elementOverride)
        attributeOverrides.Add(
            GetType(T),
            New System.Xml.Serialization.XmlAttributes With {
                .XmlRoot = New System.Xml.Serialization.XmlRootAttribute(
                    rootName)})

        Return attributeOverrides
    End Function

#Region " IDisposable "

    Private disposedValue As Boolean

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                _client.Dispose()

            End If

        End If

        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

#End Region

#End Region
End Class
